Hystrix 请求命令 & 异常处理

作者: 李多多 日期: 2020-08-07
Spring Cloud
Hystrix 请求命令 & 异常处理

1.请求命令

请求命令就是以继承类的方式来代替前面的注解方式。

接着上文,首先定义一个helloCommand:

public class HelloCommand extends HystrixCommand<String> {

RestTemplate restTemplate;

public HelloCommand(Setter setter,RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}

/**
* String类型为上面定义的泛型
* @return
* @throws Exception
*/
@Override
protected String run() throws Exception {
return restTemplate.getForObject("http://provider/hello",String.class);
}
}

调用方法:

@GetMapping("/hello2")
public void hello2(){
HelloCommand helloCommand = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("hellojava")), restTemplate);
/** 两种调用方法
* 一、直接调用【同步】
* 【注意:HelloCommand new出来之后只能调用一次,两种方法只执行一次】
* */
String execute = helloCommand.execute();
System.out.println(execute);
HelloCommand helloCommand2 = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("hellojava")), restTemplate);

/** 二、先入队,后执行 【异步】*/
String s = null;
try {
Future<String> queue = helloCommand2.queue();
s = queue.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(s);

}

 启动eureka server和provider以及hystrix ,访问http://localhost:3000/hello2 在控制台查看结果。

1.1通过注解实现请求异步调用

@HystrixCommand(fallbackMethod = "error")
public Future<String> hello2(){
return new AsyncResult<String>(){

@Override
public String invoke() {
return restTemplate.getForObject("http://provider/hello",String.class);
}
};
}
@GetMapping("/hello3")
public void hello3(){
Future<String> stringFuture = helloService.hello2();
String s = null;
try {
s = stringFuture.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(s);

}

 重启hystrix项目,访问:http://localhost:3000/hello3 如下:

image.png

1.2通过继承方式使用Hystrix, 重写继承类的 getFallback 方法实现服务容错/降级。

public class HelloCommand extends HystrixCommand<String> {

RestTemplate restTemplate;

public HelloCommand(Setter setter,RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}


@Override
protected String run() throws Exception {
return restTemplate.getForObject("http://provider/hello",String.class);
}

/**
* 请求失败的回调
* @return
*/
@Override
protected String getFallback(){
return "error-extends";
}

}

重启hystrix项目 访问hello2接口。(启动2个provider,都注册到eureka,,再关闭一个,刷新才能看到效果,与一开始的注解式方式相似)

2.异常处理

 就是当发起服务时,如果不是provider的原因导致请求调用失败,而是 consumer 中本身代码有问题导致的请求失败,即 consumer中抛出了异常,这个时候,也会自动进行服务降级,只不过这个时候降级,我们还需要知道到底哪里出错了。

如下例实例代码,如果hello方法执行时抛出异常,那么一样会进行服务降级,进入到 error 方法中,然后获取到异常的详细及信息。

@Service
public class HelloService {

@Autowired
RestTemplate restTemplate;

/**
* 在这个方法中,将发起一个远程调用,去调用provider中提供的 /hello接口
* 但是调用这个方法可能会失败,
*
* 所以在方法上面添加 @HystrixCommand ,配置fallbackMethod 属性,这个属性表示该方法调用失败时的临时替代方法
* 【专业术语:服务降级】 */
@HystrixCommand(fallbackMethod = "error")//如果希望直接抛出异常,不做服务降级 。则再加上ignoreExceptions配置(fallbackMethod = "error",ignoreExceptions = ArithmeticException.class)
public String hello(){
int i = 1 / 0;
return restTemplate.getForObject("http://provider/hello",String.class);
}


/**
* 这个方法名要和 fallbackMethod一致
* 方法返回值也要一致 【比如这里都是String类型,error也要一致】
* 此处 调用 备案方案 ,比如数据库崩了,就要去查缓存
*
* * **下面也可以继续写HystrixCommand调用error2 ,然后error2再去调用其它的方法,方法一样,依次往下,这就是【服务降级】
* * **越往下,数据的获取能力越来越容易,准确性可能降低,但不会让系统挂掉。
* * ** 这就是Hystrix 的作用: 1. 降级 2. 容错。 避免雪崩 。
*
* @return
*/
//@HystrixCommand(fallbackMethod = "error2")
public String error(Throwable t){
return "error"+t.getMessage();
}
}

这是注解的方式,也可以通过继承的方式:

public class HelloCommand extends HystrixCommand<String> {

RestTemplate restTemplate;

public HelloCommand(Setter setter,RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}

/**
* String类型为上面定义的泛型
* @return
* @throws Exception
*/
@Override
protected String run() throws Exception {
int i = 1 / 0;//测试异常
return restTemplate.getForObject("http://provider/hello",String.class);
}

/**
* 请求失败的回调
* @return
*/
@Override
protected String getFallback(){
return "error-extends"+getFailedExecutionException().getMessage();
}

}

如果是通过继承的方式来做 Hystrix ,在getFallback 方法中,我们可以通过 getExecutionException 方法来获取执行的异常信息。

另一种可能性。如果抛出异常了,我们希望异常直接抛出,不要服务降级,那么只需要配置忽略某一个异常即可:

@Override
protected String hello() {
int i = 1 / 0;//测试异常
return restTemplate.getForObject("http://provider/hello",String.class);
}

代码示例地址:https://github.com/astronger/springcloud-simple-samples